local state = {}
state.name = "CHARGING"
state.id = 4

if(SERVER) then

  state.startTime = nil
  state.lastRunTime = nil
  state.charge = 0

  function ENT:GetChargingDuration()
     return math.sqrt(self:GetEnergyPerShot()) / 6
  end

  function state.New()
    return table.Copy(state)
  end

  function state:Run(ag3)
    if(self.startTime == nil) then
      self.startTime = CurTime()
    end
  
    local chargeRequired = ag3:GetEnergyPerShot()
  
    if(self.charge < chargeRequired) then
      local elapsedTime = CurTime() - (self.lastRunTime or CurTime())
      local amountToCharge = math.min(chargeRequired - self.charge, chargeRequired / ag3:GetChargingDuration() * elapsedTime)
      
      if(ag3.HasRD) then
        local energyConsumed = ag3:ConsumeResource("energy", amountToCharge)
        self.charge = self.charge + energyConsumed
        
        if(energyConsumed < amountToCharge) then
          ag3:SetNetworkedFloat("charge", 0)
          return ag3:SetNextState(ag3.States.Idle)
        end
      else
        self.charge = self.charge + amountToCharge
      end
      
      ag3:SetNetworkedFloat("charge", self.charge / chargeRequired)
    end
    
    self.lastRunTime = CurTime()
    
    if(self.charge >= chargeRequired) then
      if(ag3:IsGrouped() == true) then
        local group = ag3:GetGroup()
        
        if(self:IsGroupCharged(group)) then
          ag3:SetNetworkedFloat("charge", 0)
          return ag3:SetNextState(ag3.States.FiringIndirect)
        elseif(self:IsGroupPreparingToFire(group) == false) then
          ag3:SetNetworkedFloat("charge", 0)
          return ag3:SetNextState(ag3.States.Idle)
        end
      else
        ag3:SetNetworkedFloat("charge", 0)
        return ag3:SetNextState(ag3.States.FiringDirect)
      end
    end
    
    return self
  end
  
  function state:IsGroupPreparingToFire(group)
    if(group == nil) then
      error("Group cannot be nil.\n")
    end
    
    for _, ag3 in ipairs(group) do
      if(ValidEntity(ag3) == false || (!ag3:IsAiming() && !ag3:IsCharging())) then
        return false
      end
    end
    
    return true
  end
  
  function state:IsGroupCharged(group)
    if(group == nil) then
      error("Group cannot be nil.\n")
    end
    
    for _, ag3 in ipairs(group) do
      if(ag3:GetNetworkedFloat("charge", 0.0) < 1.0) then
        return false
      end
    end
    
    return true
  end

end
  
ENT.States.Charging = state
